local utils = {}

utils.call = function(cb, ...)
    if utils.types.is_func(cb) then
        cb(...)
    end
end

utils.handler = function(obj, method)
    return function(...)
        if obj[method] then
            obj[method](obj, ...)
        end
    end
end

utils.types = {
    null = 'nil',
    boolean = 'boolean',
    number = 'number',
    string = 'string',
    table = 'table',
    func = 'function',
    thread = 'thread',
    userdata = 'userdata',
    is_type_of = function(v, typ)
        return type(v) == typ
    end,
    is_null = function(v)
        return utils.types.is_type_of(v, utils.types.null)
    end,
    is_number = function(v)
        return utils.types.is_type_of(v, utils.types.number)
    end,
    is_string = function(v)
        return utils.types.is_type_of(v, utils.types.string)
    end,
    is_table = function(v)
        return utils.types.is_type_of(v, utils.types.table)
    end,
    is_func = function(v)
        return utils.types.is_type_of(v, utils.types.func)
    end,
    is_boolean = function(v)
        return utils.types.is_type_of(v, utils.types.boolean)
    end,
    is_thread = function(v)
        return utils.types.is_type_of(v, utils.types.thread)
    end,
    is_userdata = function(v)
        return utils.types.is_type_of(v, utils.types.userdata)
    end,
    is_true = function(v)
        return utils.types.is_boolean(v) and v == true
    end,
    is_false = function(v)
        return utils.types.is_boolean(v) and v == false
    end
}

utils.number = {
    is_positive = function(v)
        return utils.types.is_number(v) and v > 0
    end,
    is_nagtive = function(v)
        return utils.types.is_number(v) and v < 0
    end,
    random_seed = function()
        math.randomseed(tonumber(tostring(_G):sub(8, 17)) * os.time())
    end
}

utils.expect = {
    is = function(v1, v2)
        assert(v1 == v2, string.format('%s ~= %s', v1, v2))
    end,
    no = function(v1, v2)
        assert(v1 ~= v2, string.format('%s == %s', v1, v2))
    end,
    True = function(v)
        assert(utils.types.is_true(v), 'target is false')
    end,
    False = function(v)
        assert(utils.types.is_false(v), 'target is true')
    end
}

utils.number.random_seed()
utils.uuid = {
    __uuid = math.random(128, 4096),
    get = function(_, prefix)
        utils.uuid.__uuid = utils.uuid.__uuid + 1
        return string.format('%s.%d', prefix or 'gui', utils.uuid.__uuid)
    end
}
setmetatable(utils.uuid, {__call = utils.uuid.get})

return utils
